﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if !Portable
using System.Data;
#endif
using System.Reflection;
namespace XYZShell.Helper
{
	public static class IEnumerableHelper
	{
		/// <summary>
		/// 把IDictionary中的每个Key和IEnumerable中的每个值进行组合
		/// </summary>
		/// <typeparam name="K"></typeparam>
		/// <typeparam name="V"></typeparam>
		/// <param name="diclist"></param>
		/// <returns>组合后的IDictionary列表</returns>
		public static IList<IDictionary<K, V>> ExtractListDic<K, V>( this IDictionary<K, IEnumerable<V>> diclist )
		{

			IList<IDictionary<K, V>> rtn = new List<IDictionary<K, V>>();
			if (diclist == null || diclist.Count() == 0)
				return rtn;
			var kvp0 = diclist.ElementAt( 0 );
			IEnumerable<V> v0 = kvp0.Value;
			foreach (V item in v0)
			{
				IDictionary<K, V> d = new Dictionary<K, V>();
				d.Add( kvp0.Key, item );
				rtn.Add( d );
			}

			for (int i = 1; i < diclist.Count(); i++)
			{
				List<IDictionary<K, V>> di = new List<IDictionary<K, V>>();
				var kvpi = diclist.ElementAt( i );
				IEnumerable<V> vi = kvpi.Value;
				foreach (V item in vi)
				{
					Dictionary<K, V> d = new Dictionary<K, V>();
					d.Add( kvpi.Key, item );
					di.Add( d );

				}
				rtn = CombinDicList( rtn, di ).ToList();
			}
			return rtn;
		}
		private static IEnumerable<IDictionary<K, V>> CombinDicList<K, V>( IEnumerable<IDictionary<K, V>> current, IEnumerable<IDictionary<K, V>> next )
		{
			for (int i = 0; i < current.Count(); i++)
			{
				for (int j = 0; j < next.Count(); j++)
				{
					IDictionary<K, V> tmp = new Dictionary<K, V>();
					var dicCur = current.ElementAt( i );
					foreach (var item in dicCur)
					{
						tmp.Add( item.Key, item.Value );
					}
					var dicNext = next.ElementAt( j );
					foreach (var item in dicNext)
					{
						tmp.Add( item.Key, item.Value );
					}
					yield return tmp;
				}
			}
		}


#if !Portable
		/// <summary>
		/// 转换为DataTable
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="varlist"></param>
		/// <returns></returns>
		public static DataTable ToDataTable<T>( this IEnumerable<T> varlist )
		{
			DataTable dtReturn = new DataTable();

			// column names 
			PropertyInfo[] oProps = null;

			if (varlist == null)
				return dtReturn;

			foreach (T rec in varlist)
			{
				// Use reflection to get property names, to create table, Only first time, others   will follow 
				if (oProps == null)
				{
					oProps = ( (Type)rec.GetType() ).GetProperties();
					foreach (PropertyInfo pi in oProps)
					{
						Type colType = pi.PropertyType;

						if (( colType.IsGenericType ) && ( colType.GetGenericTypeDefinition()
						== typeof( Nullable<> ) ))
						{
							colType = colType.GetGenericArguments()[0];
						}

						dtReturn.Columns.Add( new DataColumn( pi.Name, colType ) );
					}
				}

				DataRow dr = dtReturn.NewRow();

				foreach (PropertyInfo pi in oProps)
				{
					dr[pi.Name] = pi.GetValue( rec, null ) == null ? DBNull.Value : pi.GetValue
					( rec, null );
				}

				dtReturn.Rows.Add( dr );
			}
			return dtReturn;
		}

#endif
		/// <summary>
		/// 返回IEnumerable中的一部分
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="var"></param>
		/// <param name="start">开始位置</param>
		/// <param name="len">元素个数</param>
		/// <returns></returns>
		public static IEnumerable<T> SubPart<T>( this IEnumerable<T> var, int start, int len )
		{
			int index = start;
			int count = 0;
			while (index < var.Count() && count < len)
			{
				
				yield return var.ElementAt( index );
				index++;
				count++;
			}
			yield break;
		}

		/// <summary>
		/// 对所有元素进行操作
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="var"></param>
		/// <param name="func">操作的方法</param>
		/// <returns></returns>
		public static IEnumerable<T> Each<T>( this IEnumerable<T> var, Func<T, T> func )
		{
			foreach (var i in var)
			{
				yield return func( i );
			}
		}

		/// <summary>
		/// 复制源数据到当前数据(覆盖)
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="var"></param>
		/// <param name="src"></param>
		/// <returns></returns>
		public static IEnumerable<T> CopyIn<T>( this IEnumerable<T> var, IEnumerable<T> src, int index = 0 )
		{
			int i = 0;
			for (i = 0; i < index; i++)
			{
				yield return var.ElementAt( i );
			}
			int j = 0;
			for (; j < src.Count(); j++)
			{
				yield return src.ElementAt( j );
			}
			for (j += index; j < var.Count(); j++)
			{
				yield return var.ElementAt( j );
			}

		}

		/// <summary>
		/// 合并连续有序的元素
		/// </summary>
		/// <typeparam name="T">类型</typeparam>
		/// <param name="em"></param>
		/// <param name="indexSelect">索引选择器</param>
		/// <param name="mergFunc">合并函数</param>
		/// <param name="step">相邻元素的索引间隔</param>
		/// <returns></returns>
		public static IEnumerable<T> MergeSequence<T>( this IEnumerable<T> em, Func<T, int> indexSelect, Func<T, T, T> mergFunc, int step = 1 )
		{
		
			T sumElm = default( T );
			bool mergFlag = false;
			for (int i = 1; i < em.Count(); i++)
			{
				T preElm = em.ElementAt( i - 1 );
				int pre = indexSelect( preElm );

				int index = indexSelect( em.ElementAt( i ) );
				if (pre + step == index)
				{
					mergFlag = true;
					if (sumElm.Equals( default( T ) ))
					{
						sumElm = mergFunc( preElm, em.ElementAt( i ) );
					}
					else
					{
						sumElm = mergFunc( sumElm, em.ElementAt( i ) );
					}

				}
				else
				{
					if (mergFlag)
					{
						mergFlag = false;
						T tmp = sumElm;
						sumElm = default( T );
						yield return tmp;
					}
					else
					{
						yield return preElm;
					}
				}
				if (i == em.Count() - 1) //last
				{
					if (mergFlag)
					{
						yield return sumElm;
					}
					else
					{
						yield return em.Last();
					}
				}
			}
		}

		/// <summary>
		/// 合并连续的元素
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="em"></param>
		/// <param name="isSequence">连续判断</param>
		/// <param name="mergFunc">合并函数</param>
		/// <returns></returns>
		public static IEnumerable<T> MergeSequence<T>( this IEnumerable<T> em, Func<T, T, bool> isSequence, Func<T, T, T> mergFunc )
		where T : class
		{

			T sumElm = null;
			bool mergFlag = false;
			List<T> grp = new List<T>();
			for (int i = 1; i < em.Count(); i++)
			{
				T preElm = em.ElementAt( i - 1 );

				if (isSequence( preElm, em.ElementAt( i ) ))
				{
					mergFlag = true;
					if (sumElm == null)
					{

						sumElm = mergFunc( preElm, em.ElementAt( i ) );
					}
					else
					{
						sumElm = mergFunc( sumElm, em.ElementAt( i ) );
					}

				}
				else
				{
					if (mergFlag)
					{
						mergFlag = false;
						T tmp = sumElm;
						sumElm = null;
						yield return tmp;
					}
					else
					{
						yield return preElm;
					}
				}
				if (i == em.Count() - 1) //last
				{
					if (mergFlag)
					{
						yield return sumElm;
					}
					else
					{
						yield return em.Last();
					}
				}
			}
		}

		/// <summary>
		/// 对连续的元素进行分组
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="em"></param>
		/// <param name="isSequence">是否连续的判断函数</param>
		/// <param name="mergFunc">合并操作</param>
		/// <returns></returns>
		public static IEnumerable< IEnumerable<T>> GroupSequence<T>( this IEnumerable<T> em, Func<T, T, bool> isSequence, Func<T, T, T> mergFunc ) 
		{

			bool mergFlag = false;
			List<T> grp = new List<T>();
			for (int i = 1; i < em.Count(); i++)
			{
				T preElm = em.ElementAt( i - 1 );

				if (isSequence( preElm, em.ElementAt( i ) ))
				{
					mergFlag = true;
					grp.Add( preElm );
				}
				else
				{
					if (mergFlag)
					{
						mergFlag = false;
					
						List<T> tmpLst = new List<T>();
						tmpLst.AddRange( grp );
						grp.Clear();
						yield return tmpLst;
					
					}
					else
					{
						List<T> lst = new List<T>();
						lst.Add( preElm );
						yield return lst;
					}
				}
				if (i == em.Count() - 1) //last
				{
					if (mergFlag)
					{
						yield return grp;
					}
					else
					{
						List<T> lst = new List<T>();
						lst.Add( em.Last() );
						yield return lst;
					}
				}
			}
		}

		/// <summary>
		/// 对连续的元素进行分组
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="em"></param>
		/// <param name="isSequence">是否连续的判断函数</param>
		/// <returns></returns>
		public static IEnumerable<IEnumerable<T>> GroupSequence<T>( this IEnumerable<T> em, Func<T, T, bool> isSequence )
		{
			if (em.Count()==1)
			{
				List<T> lst = new List<T>(em);
				yield return lst;
			}
			bool mergFlag = false;
			List<T> grp = new List<T>();
			for (int i = 1; i < em.Count(); i++)
			{
				T preElm = em.ElementAt( i - 1 );

				if (isSequence( preElm, em.ElementAt( i ) ))
				{
					mergFlag = true;
					grp.AddIfNotExist( preElm );
					grp.Add( em.ElementAt( i ) );
				}
				else
				{
					if (mergFlag)
					{
						mergFlag = false;

						List<T> tmpLst = new List<T>(grp);
						grp.Clear();
						yield return tmpLst;

					}
					else
					{
						List<T> lst = new List<T>();
						lst.Add( preElm );
						yield return lst;
					}
				}
				if (i == em.Count() - 1) //last
				{
					if (mergFlag)
					{
						yield return grp;
					}
					else
					{
						List<T> lst = new List<T>();
						lst.Add( em.Last() );
						yield return lst;
					}
				}
			}
		}

		/// <summary>
		/// 展开两级列表为一级
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="em"></param>
		/// <returns></returns>
		public static IEnumerable<T> ExpandOneLevel<T>(this IEnumerable<IEnumerable<T>> em)
		{
			foreach (var items in em)
			{
				foreach (var item in items)
				{
					yield return item;
				}
			}
		}


		/// <summary>
		/// 打乱元素的顺序,即洗牌
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="em"></param>
		/// <returns></returns>
		public static IEnumerable<T> Shuffle<T>( this IEnumerable<T> em )
		{
			Random r = new Random();
			IList<T> lst = em.ToList();

			while (lst.Count > 0)
			{
				int index = r.Next( lst.Count );
				var item= lst[index];				
				lst.RemoveAt( index );
				yield return item;
			}

		}
	}
}
